#include "citymap.h"
#include "ui_citymap.h"
#include <QPushButton>
#include <QString>
#include <QPainter>
#include <QMouseEvent>
#include <vector>
#include<onecity.h>

const int INF = 0x3f3f3f3f;
const int NN = 10;

//城市内部类
citymap::citymap(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::citymap)
{
    ui->setupUi(this);

    this->getx["school"]=100;
    this->gety["school"]=400;
    this->getwidth["school"]=61;
    this->getheight["school"]=91;

    this->getx["hospital"]=ui->hospital->pos().rx();
    this->gety["hospital"]=ui->hospital->pos().ry();
    this->getwidth["hospital"]=ui->hospital->width();
    this->getheight["hospital"]=ui->hospital->height();

    this->getx["mall"]=ui->mall->pos().rx();
    this->gety["mall"]=ui->mall->pos().ry();
    this->getwidth["mall"]=ui->mall->width();
    this->getheight["mall"]=ui->mall->height();

    this->getx["cafe"]=ui->cafe->pos().rx();
    this->gety["cafe"]=ui->cafe->pos().ry();
    this->getwidth["cafe"]=ui->cafe->width();
    this->getheight["cafe"]=ui->cafe->height();

    this->getx["park"]=ui->park->pos().rx();
    this->gety["park"]=ui->park->pos().ry();
    this->getwidth["park"]=ui->park->width();
    this->getheight["park"]=ui->park->height();

    this->getx["business"]=ui->business->pos().rx();
    this->gety["business"]=ui->business->pos().ry();
    this->getwidth["business"]=ui->business->width();
    this->getheight["business"]=ui->business->height();




    this->setWindowTitle("多功能导航系统V1.0");
    this->setWindowIcon(QIcon("://res/nav.png"));
    this->setFixedSize(1120,693);
    // 学校特殊按钮

    school->setText("学校");
    school->setObjectName(QString::fromUtf8("school"));
    school->setGeometry(QRect(50, 420, 111, 71));
    QIcon iconschool;
    iconschool.addFile(QString::fromUtf8(":/res/school.png"), QSize(), QIcon::Normal, QIcon::Off);
    school->setIcon(iconschool);
    school->setIconSize(QSize(50, 50));
    school->setParent(ui->site);






    // 地图窗口样式
    ui->site->setStyleSheet(QString::fromUtf8("#site{border:3px solid black}"));

    //添加起点
    /****注意！这里排放顺序要和在邻接矩阵的顺序一致！*****/
    ui->startBox->addItem("学校");
    ui->startBox->addItem("医院");
    ui->startBox->addItem("商场");
    ui->startBox->addItem("餐饮");
    ui->startBox->addItem("公园");
    ui->startBox->addItem("工作区");
    //添加终点
    ui->endBox->addItem("学校");
    ui->endBox->addItem("医院");
    ui->endBox->addItem("商场");
    ui->endBox->addItem("餐饮");
    ui->endBox->addItem("公园");
    ui->endBox->addItem("工作区");

    /*
        注意：是否要写一个判断，如果起点终点相同则弹出提示。
    */

    //地图定位信息的实现（单击事件）
    /*
     留一个可优化的点，如何将这个模块的抽象层次提高
    */
    connect(school,&QPushButton::clicked,[=](){
        ui->nodeinfo->setText("");//清空原有信息
        QString sitename = "学校";
        int siteid = cc.getId["school"];
        ui->nodeinfo->insertPlainText("场景名称： "+sitename+"\n"
                              +"位置：("+QString::number(cc.site[siteid].x,10)
                              +","+QString::number(cc.site[siteid].y,10)+")\n"
                              +"相邻区域： \n");
        int t=0;
        for(int i=0;i<cc.snum;i++){
            if(cc.dist[siteid][i]!=INF){
                ui->nodeinfo->insertPlainText(sitename+"距离"+
                                      QString::fromStdString(cc.site[i].name)
                                      +QString::number(cc.dist[siteid][i],10)+"公里\n");
                t++;
            }
        }
        if(t==0){
            ui->nodeinfo->insertPlainText("该城市没有相邻城市！");
        }

    });

    connect(ui->hospital,&QPushButton::clicked,[=](){
        ui->nodeinfo->setText("");//清空原有信息
        QString sitename = "医院";
        int siteid = cc.getId["hospital"];
        ui->nodeinfo->insertPlainText("场景名称： "+sitename+"\n"
                              +"位置：("+QString::number(cc.site[siteid].x,10)
                              +","+QString::number(cc.site[siteid].y,10)+")\n"
                              +"相邻区域： \n");
        int t=0;
        for(int i=0;i<cc.snum;i++){
            if(cc.dist[siteid][i]!=INF){
                ui->nodeinfo->insertPlainText(sitename+"距离"+
                                      QString::fromStdString(cc.site[i].name)
                                      +QString::number(cc.dist[siteid][i],10)+"公里\n");
                t++;
            }
        }
        if(t==0){
            ui->nodeinfo->insertPlainText("该城市没有相邻城市！");
        }

    });

    connect(ui->mall,&QPushButton::clicked,[=](){
        ui->nodeinfo->setText("");//清空原有信息
        QString sitename = "商场";
        int siteid = cc.getId["mall"];
        ui->nodeinfo->insertPlainText("场景名称： "+sitename+"\n"
                              +"位置：("+QString::number(cc.site[siteid].x,10)
                              +","+QString::number(cc.site[siteid].y,10)+")\n"
                              +"相邻区域： \n");
        int t=0;
        for(int i=0;i<cc.snum;i++){
            if(cc.dist[siteid][i]!=INF){
                ui->nodeinfo->insertPlainText(sitename+"距离"+
                                      QString::fromStdString(cc.site[i].name)
                                      +QString::number(cc.dist[siteid][i],10)+"公里\n");
                t++;
            }
        }
        if(t==0){
            ui->nodeinfo->insertPlainText("该城市没有相邻城市！");
        }

    });

    connect(ui->cafe,&QPushButton::clicked,[=](){
        ui->nodeinfo->setText("");//清空原有信息
        QString sitename = "餐饮";
        int siteid = cc.getId["cafe"];
        ui->nodeinfo->insertPlainText("场景名称： "+sitename+"\n"
                              +"位置：("+QString::number(cc.site[siteid].x,10)
                              +","+QString::number(cc.site[siteid].y,10)+")\n"
                              +"相邻区域： \n");
        int t=0;
        for(int i=0;i<cc.snum;i++){
            if(cc.dist[siteid][i]!=INF){
                ui->nodeinfo->insertPlainText(sitename+"距离"+
                                      QString::fromStdString(cc.site[i].name)
                                      +QString::number(cc.dist[siteid][i],10)+"公里\n");
                t++;
            }
        }
        if(t==0){
            ui->nodeinfo->insertPlainText("该城市没有相邻城市！");
        }

    });

    connect(ui->park,&QPushButton::clicked,[=](){
        ui->nodeinfo->setText("");//清空原有信息
        QString sitename = "公园";
        int siteid = cc.getId["park"];
        ui->nodeinfo->insertPlainText("场景名称： "+sitename+"\n"
                              +"位置：("+QString::number(cc.site[siteid].x,10)
                              +","+QString::number(cc.site[siteid].y,10)+")\n"
                              +"相邻区域： \n");
        int t=0;
        for(int i=0;i<cc.snum;i++){
            if(cc.dist[siteid][i]!=INF){
                ui->nodeinfo->insertPlainText(sitename+"距离"+
                                      QString::fromStdString(cc.site[i].name)
                                      +QString::number(cc.dist[siteid][i],10)+"公里\n");
                t++;
            }
        }
        if(t==0){
            ui->nodeinfo->insertPlainText("该城市没有相邻城市！");
        }

    });

    connect(ui->business,&QPushButton::clicked,[=](){
        ui->nodeinfo->setText("");//清空原有信息
        QString sitename = "工作区";
        int siteid = cc.getId["business"];
        ui->nodeinfo->insertPlainText("场景名称： "+sitename+"\n"
                              +"位置：("+QString::number(cc.site[siteid].x,10)
                              +","+QString::number(cc.site[siteid].y,10)+")\n"
                              +"相邻区域： \n");
        int t=0;
        for(int i=0;i<cc.snum;i++){
            if(cc.dist[siteid][i]!=INF){
                ui->nodeinfo->insertPlainText(sitename+"距离"+
                                      QString::fromStdString(cc.site[i].name)
                                      +QString::number(cc.dist[siteid][i],10)+"公里\n");
                t++;
            }
        }
        if(t==0){
            ui->nodeinfo->insertPlainText("该城市没有相邻城市！");
        }

    });

    /*-------------------------------------------------导航算法----------------------------------------------------------------------------*/
    connect(ui->beginBtn,&QPushButton::clicked,[=](){
        ui->navinfo->setText("");
        //起点终点编号id
        int startid = ui->startBox->currentIndex();
        int endid = ui->endBox->currentIndex();
        ui->navinfo->insertPlainText("从"+QString::fromStdString(cc.site[startid].name)+"出发，到"+QString::fromStdString(cc.site[endid].name)+"\n\n");

        //出行方式的获取
        if(ui->train->isChecked()){
            ui->navinfo->insertPlainText("选择地铁\n\n");
        }
        else if(ui->car->isChecked()){
            ui->navinfo->insertPlainText("选择驾车\n\n");
        }
        else if(ui->walk->isChecked()){
            ui->navinfo->insertPlainText("选择骑行\n");
        }
        else if(ui->bike->isChecked()){
            ui->navinfo->insertPlainText("选择步行\n");
        }

        //出行策略的获取
        if(ui->timefirst->isChecked()){
            ui->navinfo->insertPlainText("时间优先\n\n");
        }
        if(ui->disfirst->isChecked()){
            ui->navinfo->insertPlainText("距离优先\n\n");
        }

        /***********************最短路算法***********************/
        //Dijkstra+路径记录//Floyd先计算全局最短路径
        int totm[NN][NN];
        for(int i=0;i<cc.snum;i++){
            for(int j=0;j<cc.snum;j++){
                totm[i][j]=cc.dist[i][j];
            }
        }

        for(int k=0;k<cc.snum;k++){
            for(int i=0;i<cc.snum;i++){
                for(int j=0;j<cc.snum;j++){
                    if(totm[i][j]>cc.dist[i][k]+cc.dist[k][j])
                        totm[i][j]=cc.dist[i][k]+cc.dist[k][j];
                }
            }
        }

        int u=startid;
        if(ui->bike->isChecked()){
            //骑行和步行都不需要计算中转，两点间的道路上没有第三个场所，所以最短距离就是两点间直达距离，
            ui->navinfo->insertPlainText("提倡选择绿色方式，已为您推荐两点最短距离！\n");
            ui->navinfo->insertPlainText("全程"+QString::number(cc.di[startid][endid],10)+"公里\n");
            ui->navinfo->insertPlainText("大约需要"+QString::number(cc.spb[startid][endid])+"小时\n");
        }

        if(ui->walk->isChecked()){
            //骑行和步行都不需要计算中转，两点间的道路上没有第三个场所，所以最短距离就是两点间直达距离，
            ui->navinfo->insertPlainText("提倡选择绿色方式，已为您推荐两点最短距离！\n");
            ui->navinfo->insertPlainText("全程"+QString::number(cc.di[startid][endid],10)+"公里\n");
            ui->navinfo->insertPlainText("大约需要"+QString::number(cc.spw[startid][endid])+"小时\n");
        }

        if(ui->car->isChecked()){
            //时间优先
            if(ui->timefirst->isChecked()){
                double mint[NN];
                int pre[NN];
                int vis[NN];
                memset(mint,INF,sizeof mint);
                memset(pre,-1,sizeof pre);
                memset(vis,0,sizeof vis);
                for(int i=0;i<cc.snum;i++){
                    mint[i]=cc.spc[u][i];
                }
                for(int i=0;i<cc.snum;i++){
                    if(mint[i]<INF/2)
                        pre[i]=startid;//有通路的时候是前驱均为起点
                    else {
                        pre[i]=-1;//没通路的时候前驱为-1
                    }
                }//记录前一个点
                vis[u]=1;
                int ru=u;
                for(int i=1;i<cc.snum;i++){
                    double minn=INF/2;
                    for(int j=0;j<cc.snum;j++){
                        if(mint[j]<minn&&!vis[j]){
                            minn=mint[j];
                            ru=j;
                        }
                    }
                    vis[ru]=1;
                    for(int j=0;j<cc.snum;j++){
                        if(cc.spc[ru][j]<INF/2&&mint[j]>minn+cc.spc[ru][j]){
                            mint[j]=minn+cc.spc[ru][j];
                            pre[j]=ru;
                        }
                    }
                }
                if(pre[endid]==-1){
                    ui->navinfo->insertPlainText("暂无通路\n");
                }
                else{
                    int ii=endid;
                    int re[NN];
                    int k=0;
                    re[k++]=endid;
                    while(pre[ii]!=startid){
                        re[k++]=pre[ii];
                        ii=pre[ii];
                    }
                    re[k]=startid;
                    ui->navinfo->insertPlainText("全程"+QString::number(totm[startid][endid],10)+"公里\n");
                    ui->navinfo->insertPlainText("大约需要"+QString::number(mint[endid])+"小时\n");
                    ui->navinfo->insertPlainText("沿途经过\n");
                    int i=0;
                    for(int j=k;j>=0;j--){
                        if(j!=0){
                            this->cx[i]=this->getx[cc.site[re[j]].ename]+this->getwidth[cc.site[re[j]].ename];
                            this->cy[i]=this->gety[cc.site[re[j]].ename]+this->getheight[cc.site[re[j]].ename];
                            i++;
                            ui->navinfo->insertPlainText(QString::fromStdString(cc.site[re[j]].name)+"->");
                        }
                        else {
                            this->cx[i]=this->getx[cc.site[re[j]].ename]+this->getwidth[cc.site[re[j]].ename];
                            this->cy[i]=this->gety[cc.site[re[j]].ename]+this->getheight[cc.site[re[j]].ename];
                            i++;
                            ui->navinfo->insertPlainText(QString::fromStdString(cc.site[re[j]].name)+"\n");
                        }
                    }
                    this->cx[i]=-1;
                    this->cy[i]=-1;
                }
            }
            //距离优先
            else if(ui->disfirst->isChecked()){
                double mint[NN];
                int pre[NN];
                int vis[NN];
                memset(mint,INF,sizeof mint);
                memset(pre,-1,sizeof pre);
                memset(vis,0,sizeof vis);
                for(int i=0;i<cc.snum;i++){
                    mint[i]=cc.dist[u][i];
                }
                for(int i=0;i<cc.snum;i++){
                    if(mint[i]<INF/2)
                        pre[i]=startid;//有通路的时候是前驱均为起点
                    else {
                        pre[i]=-1;//没通路的时候前驱为-1
                    }
                }//记录前一个点
                vis[u]=1;
                int ru=u;
                for(int i=1;i<cc.snum;i++){
                    double minn=INF/2;
                    for(int j=0;j<cc.snum;j++){
                        if(mint[j]<minn&&!vis[j]){
                            minn=mint[j];
                            ru=j;
                        }
                    }
                    vis[ru]=1;
                    for(int j=0;j<cc.snum;j++){
                        if(cc.dist[ru][j]<INF/2&&mint[j]>minn+cc.dist[ru][j]){
                            mint[j]=minn+cc.dist[ru][j];
                            pre[j]=ru;
                        }
                    }
                }
                if(pre[endid]==-1){
                    ui->navinfo->insertPlainText("暂无通路\n");
                }
                else{
                    int ii=endid;
                    int re[NN];
                    int k=0;
                    re[k++]=endid;
                    while(pre[ii]!=startid){
                        re[k++]=pre[ii];
                        ii=pre[ii];
                    }
                    re[k]=startid;
                    //最短路径下所需时间
                    double mtt=0;
                    for(int i=0;i<k-1;i++){
                        mtt+=cc.dist[re[i]][re[i+1]]*1.0/cc.spc[re[i]][re[i+1]];
                    }
                    ui->navinfo->insertPlainText("全程"+QString::number(totm[startid][endid],10)+"公里\n");
                    ui->navinfo->insertPlainText("大约需要"+QString::number(mtt)+"小时\n");
                    ui->navinfo->insertPlainText("沿途经过\n");
                    int i=0;
                    for(int j=k;j>=0;j--){
                        if(j!=0){
                            this->cx[i]=this->getx[cc.site[re[j]].ename]+this->getwidth[cc.site[re[j]].ename];
                            this->cy[i]=this->gety[cc.site[re[j]].ename]+this->getheight[cc.site[re[j]].ename];
                            i++;
                            ui->navinfo->insertPlainText(QString::fromStdString(cc.site[re[j]].name)+"->");
                        }
                        else {
                            this->cx[i]=this->getx[cc.site[re[j]].ename]+this->getwidth[cc.site[re[j]].ename];
                            this->cy[i]=this->gety[cc.site[re[j]].ename]+this->getheight[cc.site[re[j]].ename];
                            i++;
                            ui->navinfo->insertPlainText(QString::fromStdString(cc.site[re[j]].name)+"\n");
                        }
                    }
                    this->cx[i]=-1;
                    this->cy[i]=-1;
                }
            }
        }
        else if(ui->train->isChecked()){
            //地铁通常没有拥堵，选择最短时间和最短距离数据相同
            double mint[NN];
            int pre[NN];
            int vis[NN];
            memset(mint,INF,sizeof mint);
            memset(pre,-1,sizeof pre);
            memset(vis,0,sizeof vis);
            for(int i=0;i<cc.snum;i++){
                mint[i]=cc.spt[u][i];
            }
            for(int i=0;i<cc.snum;i++){
                if(mint[i]<INF/2)
                    pre[i]=startid;//有通路的时候是前驱均为起点
                else {
                    pre[i]=-1;//没通路的时候前驱为-1
                }
            }//记录前一个点
            vis[u]=1;
            int ru=u;
            for(int i=1;i<cc.snum;i++){
                double minn=INF/2;
                for(int j=0;j<cc.snum;j++){
                    if(mint[j]<minn&&!vis[j]){
                        minn=mint[j];
                        ru=j;
                    }
                }
                vis[ru]=1;
                for(int j=0;j<cc.snum;j++){
                    if(cc.spt[ru][j]<INF/2&&mint[j]>minn+cc.spt[ru][j]){
                        mint[j]=minn+cc.spt[ru][j];
                        pre[j]=ru;
                    }
                }
            }
            if(pre[endid]==-1){
                ui->navinfo->insertPlainText("暂无通路\n");
            }
            else{
                int ii=endid;
                int re[NN];
                int k=0;
                re[k++]=endid;
                while(pre[ii]!=startid){
                    re[k++]=pre[ii];
                    ii=pre[ii];
                }
                re[k]=startid;
                ui->navinfo->insertPlainText("全程"+QString::number(totm[startid][endid],10)+"公里\n");
                ui->navinfo->insertPlainText("大约需要"+QString::number(mint[endid])+"小时\n");
                ui->navinfo->insertPlainText("沿途经过\n");
                int i=0;
                for(int j=k;j>=0;j--){
                    if(j!=0){
                        this->cx[i]=this->getx[cc.site[re[j]].ename]+this->getwidth[cc.site[re[j]].ename];
                        this->cy[i]=this->gety[cc.site[re[j]].ename]+this->getheight[cc.site[re[j]].ename];
                        i++;
                        ui->navinfo->insertPlainText(QString::fromStdString(cc.site[re[j]].name)+"->");
                    }
                    else {
                        this->cx[i]=this->getx[cc.site[re[j]].ename]+this->getwidth[cc.site[re[j]].ename];
                        this->cy[i]=this->gety[cc.site[re[j]].ename]+this->getheight[cc.site[re[j]].ename];
                        i++;
                        ui->navinfo->insertPlainText(QString::fromStdString(cc.site[re[j]].name)+"\n");
                    }
                }
                this->cx[i]=-1;
                this->cy[i]=-1;
            }
        }
        this->repaint();
    });
}

citymap::~citymap()
{
    delete ui;
}
void citymap::paintEvent(QPaintEvent *ev)
{
    QPainter painter(this);
    QPixmap pix,pix2;
    // 画背景图
    pix.load(":/res/mapbg.jpeg");
    painter.drawPixmap(ui->site->geometry(),pix);
    //画坐标
    pix2.load(":/res/cursor.png");
    painter.drawPixmap(px-15,py-50,40,50,pix2);
    //画初始道路
    QPen pen1,pen2;
    pen1.setWidth(1);
    pen1.setColor(QColor(Qt::black));
    pen2.setWidth(3);
    pen2.setColor(QColor(Qt::red));
    painter.setPen(pen1);

    painter.drawLine(QPoint(school->pos().x()+(school->width()),school->pos().y()+(school->height())),
                     QPoint(ui->hospital->pos().x()+(ui->hospital->width()),ui->hospital->pos().y()+(ui->hospital->height())));
    painter.drawLine(QPoint(school->pos().x()+(school->width()),school->pos().y()+(school->height())),
                     QPoint(ui->cafe->pos().x()+(ui->cafe->width()),ui->cafe->pos().y()+(ui->cafe->height())));
    painter.drawLine(QPoint(school->pos().x()+(school->width()),school->pos().y()+(school->height())),
                     QPoint(ui->business->pos().x()+(ui->business->width()),ui->business->pos().y()+(ui->business->height())));


    painter.drawLine(QPoint(ui->hospital->pos().x()+(ui->hospital->width()),ui->hospital->pos().y()+(ui->hospital->height())),
                     QPoint(ui->mall->pos().x()+(ui->mall->width()),ui->mall->pos().y()+(ui->mall->height())));
    painter.drawLine(QPoint(ui->hospital->pos().x()+(ui->hospital->width()),ui->hospital->pos().y()+(ui->hospital->height())),
                     QPoint(ui->cafe->pos().x()+(ui->cafe->width()),ui->cafe->pos().y()+(ui->cafe->height())));
    painter.drawLine(QPoint(ui->hospital->pos().x()+(ui->hospital->width()),ui->hospital->pos().y()+(ui->hospital->height())),
                     QPoint(ui->park->pos().x()+(ui->park->width()),ui->park->pos().y()+(ui->park->height())));
    painter.drawLine(QPoint(ui->hospital->pos().x()+(ui->hospital->width()),ui->hospital->pos().y()+(ui->hospital->height())),
                     QPoint(ui->business->pos().x()+(ui->business->width()),ui->business->pos().y()+(ui->business->height())));

    painter.drawLine(QPoint(ui->mall->pos().x()+(ui->mall->width()),ui->mall->pos().y()+(ui->mall->height())),
                     QPoint(ui->cafe->pos().x()+(ui->cafe->width()),ui->cafe->pos().y()+(ui->cafe->height())));
    painter.drawLine(QPoint(ui->mall->pos().x()+(ui->mall->width()),ui->mall->pos().y()+(ui->mall->height())),
                     QPoint(ui->park->pos().x()+(ui->park->width()),ui->park->pos().y()+(ui->park->height())));
    painter.drawLine(QPoint(ui->mall->pos().x()+(ui->mall->width()),ui->mall->pos().y()+(ui->mall->height())),
                     QPoint(ui->business->pos().x()+(ui->business->width()),ui->business->pos().y()+(ui->business->height())));

    painter.drawLine(QPoint(ui->cafe->pos().x()+(ui->cafe->width()),ui->cafe->pos().y()+(ui->cafe->height())),
                     QPoint(ui->park->pos().x()+(ui->park->width()),ui->park->pos().y()+(ui->park->height())));
    painter.drawLine(QPoint(ui->cafe->pos().x()+(ui->cafe->width()),ui->cafe->pos().y()+(ui->cafe->height())),
                     QPoint(ui->business->pos().x()+(ui->business->width()),ui->business->pos().y()+(ui->business->height())));

    painter.drawLine(QPoint(ui->park->pos().x()+(ui->park->width()),ui->park->pos().y()+(ui->park->height())),
                     QPoint(ui->business->pos().x()+(ui->business->width()),ui->business->pos().y()+(ui->business->height())));
    if(cx[0]!=0 && cy[0]!=0){
        pen2.setWidth(3);
        pen2.setColor(QColor(Qt::red));
        painter.setPen(pen2);

        for(int i=0;i<6;i++){
            if(cx[i+1]==-1 && cy[i+1]==-1) break;
            painter.drawLine(QPoint(cx[i],cy[i]),QPoint(cx[i+1],cy[i+1]));
        }
    }

}

void citymap::mousePressEvent(QMouseEvent *ev)
{
    int x = ev->x();
    int y = ev->y();
    if(x>=70 && x<=(70+571) && y>=40 && y<=(40+561)){
        Qt::MouseButton mbtn = ev->button();
        if(mbtn==Qt::LeftButton){
            this->px=x;
            this->py=y;
            this->repaint();
            cout<<this->px<<" "<<this->py<<endl;
        }
    }
}
